home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / TCPSUBR.C < prev    next >
C/C++ Source or Header  |  1990-06-13  |  7KB  |  328 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8. struct tcb *tcbs[NTCB];
  9. int16 tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  10. int32 tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  11. int32 tcp_timout = SEC2TICK(TIMOUT); /* Transient state timeout */
  12.  
  13. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  14. struct tcb *
  15. lookup_tcb(conn)
  16. struct connection *conn;
  17. {
  18.     register struct tcb *tcb;
  19.     int16 hash_tcb();
  20.  
  21.     tcb = tcbs[hash_tcb(conn)];
  22.     while(tcb != NULLTCB){
  23.         /* Yet another structure compatibility hack */
  24.         if(conn->local.address == tcb->conn.local.address
  25.          && conn->remote.address == tcb->conn.remote.address
  26.          && conn->local.port == tcb->conn.local.port
  27.          && conn->remote.port == tcb->conn.remote.port)
  28.             break;
  29.         tcb = tcb->next;
  30.     }
  31.     return tcb;
  32. }
  33.  
  34. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  35. struct tcb *
  36. create_tcb(conn)
  37. struct connection *conn;
  38. {
  39.     register struct tcb *tcb;
  40.     void tcp_timeout(),reset_tcp(),tcp_msl();
  41.     void link_tcb();
  42.  
  43.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  44.         return tcb;
  45.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  46.         return NULLTCB;
  47.     ASSIGN(tcb->conn,*conn);
  48.  
  49.     tcb->cwind = tcb->mss = tcp_mss;
  50.     tcb->ssthresh = 65535;
  51.     tcb->srtt = tcp_irtt;
  52.     /* Initialize timer intervals */
  53.     tcb->timer.start = MS2TICK(tcb->srtt);
  54.     tcb->timer.func = tcp_timeout;
  55.     tcb->timer.arg = (char *)tcb;
  56.     tcb->timeout.start = tcp_timout;
  57.     tcb->timeout.func = reset_tcp;
  58.     tcb->timeout.arg = (char *)tcb;
  59.     tcb->rtt_timer.start = MAX_TIME; /* Largest possible value */
  60.  
  61.     link_tcb(tcb);
  62.     return tcb;
  63. }
  64.  
  65. /* Close our TCB */
  66. void
  67. close_self(tcb,reason)
  68. register struct tcb *tcb;
  69. char reason;
  70. {
  71.     struct reseq *rp,*rp1;
  72.  
  73.     stop_timer(&tcb->timer);
  74.     stop_timer(&tcb->timeout);
  75.     stop_timer(&tcb->rtt_timer);
  76.     tcb->reason = reason;
  77.  
  78.     /* Flush reassembly queue; nothing more can arrive */
  79.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  80.         rp1 = rp->next;
  81.         free_p(rp->bp);
  82.         free((char *)rp);
  83.     }
  84.     tcb->reseq = NULLRESEQ;
  85.     setstate(tcb,CLOSED);
  86. }
  87.  
  88. /* Determine initial sequence number */
  89. int32
  90. iss()
  91. {
  92.     static int32 seq;
  93.  
  94.     seq += 250000;
  95.     return seq;
  96. }
  97.  
  98. /* Sequence number comparisons
  99.  * Return true if x is between low and high inclusive,
  100.  * false otherwise
  101.  */
  102. int
  103. seq_within(x,low,high)
  104. register int32 x,low,high;
  105. {
  106.     if(low <= high){
  107.         if(low <= x && x <= high)
  108.             return 1;
  109.     } else {
  110.         if(low >= x && x >= high)
  111.             return 1;
  112.     }
  113.     return 0;
  114. }
  115. int
  116. seq_lt(x,y)
  117. register int32 x,y;
  118. {
  119.     return (long)(x-y) < 0;
  120. }
  121. int
  122. seq_le(x,y)
  123. register int32 x,y;
  124. {
  125.     return (long)(x-y) <= 0;
  126. }
  127. int
  128. seq_gt(x,y)
  129. register int32 x,y;
  130. {
  131.     return (long)(x-y) > 0;
  132. }
  133. int
  134. seq_ge(x,y)
  135. register int32 x,y;
  136. {
  137.     return (long)(x-y) >= 0;
  138. }
  139.  
  140. /* Hash a connect structure into the hash chain header array */
  141. static int16
  142. hash_tcb(conn)
  143. struct connection *conn;
  144. {
  145.     register int16 hval;
  146.  
  147.     /* Compute hash function on connection structure */
  148.     hval = hiword(conn->remote.address);
  149.     hval ^= loword(conn->remote.address);
  150.     hval ^= hiword(conn->local.address);
  151.     hval ^= loword(conn->local.address);
  152.     hval ^= conn->remote.port;
  153.     hval ^= conn->local.port;
  154.     hval %= NTCB;
  155.     return hval;
  156. }
  157. /* Insert TCB at head of proper hash chain */
  158. void
  159. link_tcb(tcb)
  160. register struct tcb *tcb;
  161. {
  162.     register struct tcb **tcbhead;
  163.     int16 hash_tcb();
  164.     /*char i_state;*/
  165.  
  166.     tcb->prev = NULLTCB;
  167.     /*i_state = disable();*/
  168.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  169.     tcb->next = *tcbhead;
  170.     if(tcb->next != NULLTCB){
  171.         tcb->next->prev = tcb;
  172.     }
  173.     *tcbhead = tcb;
  174.     /*restore(i_state);*/
  175. }
  176. /* Remove TCB from whatever hash chain it may be on */
  177. void
  178. unlink_tcb(tcb)
  179. register struct tcb *tcb;
  180. {
  181.     register struct tcb **tcbhead;
  182.     int16 hash_tcb();
  183.     /*char i_state;*/
  184.  
  185.     /*i_state = disable();*/
  186.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  187.     if(*tcbhead == tcb)
  188.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  189.     if(tcb->prev != NULLTCB)
  190.         tcb->prev->next = tcb->next;
  191.     if(tcb->next != NULLTCB)
  192.         tcb->next->prev = tcb->prev;
  193.     /*restore(i_state);*/
  194. }
  195. void
  196. setstate(tcb,newstate)
  197. register struct tcb *tcb;
  198. register char newstate;
  199. {
  200.     register char oldstate;
  201.     int16 window;
  202.  
  203.     oldstate = tcb->state;
  204.     switch (tcb->state = newstate)
  205.     {
  206.     case ESTABLISHED:
  207.     case TIME_WAIT:
  208.         stop_timer(&tcb->timeout);    /* Left transient state */
  209.         break;
  210.     case FINWAIT2:
  211.     case CLOSED:
  212.         start_timer(&tcb->timeout);    /* Enter transient state */
  213.         break;
  214.     }
  215.     if(tcb->s_upcall){
  216.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  217.     }
  218.     /* Notify the user that he can begin sending data */
  219.     if(tcb->t_upcall && newstate == ESTABLISHED){
  220.         window = min(tcb->cwind,tcb->snd.wnd);
  221.         window = min(window,tcb->window);
  222.         window = max(1,window);
  223.         (*tcb->t_upcall)(tcb,window - tcb->sndcnt);
  224.     }
  225. }
  226. /* Convert TCP header in host format into mbuf ready for transmission,
  227.  * link in data (if any), and compute checksum
  228.  */
  229. struct mbuf *
  230. htontcp(tcph,data,ph)
  231. struct tcp *tcph;
  232. struct mbuf *data;
  233. struct pseudo_header *ph;
  234. {
  235.     int16 hdrlen;
  236.     struct mbuf *bp;
  237.     register char *cp;
  238.     int16 csum;
  239.  
  240.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  241.  
  242.     if((bp = pushdown(data,hdrlen)) == NULLBUF){
  243.         free_p(data);
  244.         return NULLBUF;
  245.     }
  246.     cp = bp->data;
  247.     cp = put16(cp,tcph->source);
  248.     cp = put16(cp,tcph->dest);
  249.     cp = put32(cp,tcph->seq);
  250.     cp = put32(cp,tcph->ack);
  251.     *cp++ = hdrlen << 2;    /* Offset field */
  252.     *cp++ = tcph->flags;
  253.     cp = put16(cp,tcph->wnd);
  254.     *cp++ = 0;    /* Zero out checksum field */
  255.     *cp++ = 0;
  256.     cp = put16(cp,tcph->up);
  257.  
  258.     if(tcph->mss != 0){
  259.         *cp++ = MSS_KIND;
  260.         *cp++ = MSS_LENGTH;
  261.         cp = put16(cp,tcph->mss);
  262.     }
  263.     csum = cksum(ph,bp,ph->length);
  264.     cp = &bp->data[16];    /* Checksum field */
  265.     *cp++ = csum >> 8;
  266.     *cp = csum;
  267.  
  268.     return bp;
  269. }
  270. /* Pull TCP header off mbuf */
  271. int
  272. ntohtcp(tcph,bpp)
  273. struct tcp *tcph;
  274. struct mbuf **bpp;
  275. {
  276.     int16 hdrlen;
  277.     int16 i,optlen;
  278.     char tcphead[20];
  279.  
  280.     if(pullup(bpp,tcphead,20) != 20)
  281.         return -1;
  282.  
  283.     tcph->source = get16(tcphead);
  284.     tcph->dest = get16(tcphead + 2);
  285.     tcph->seq = get32(tcphead + 4);
  286.     tcph->ack = get32(tcphead + 8);
  287.     hdrlen = (tcphead[12] & 0xf0) >> 2;
  288.     tcph->flags = tcphead[13];
  289.     tcph->wnd = get16(tcphead + 14);
  290.     tcph->up = get16(tcphead + 18);
  291.     tcph->mss = 0;
  292.  
  293.     /* Check for option field. Only space for one is allowed, but
  294.      * since there's only one TCP option (MSS) this isn't a problem
  295.      */
  296.     if(hdrlen < TCPLEN)
  297.         return -1;    /* Header smaller than legal minimum */
  298.     if(hdrlen == TCPLEN)
  299.         return hdrlen;    /* No options, all done */
  300.  
  301.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  302.         /* Remainder too short for options length specified */
  303.         return -1;
  304.     }
  305.     /* Process options */
  306.     for(i=TCPLEN; i < hdrlen;){
  307.         switch(pullchar(bpp)){
  308.         case EOL_KIND:
  309.             i++;
  310.             goto eol;    /* End of options list */
  311.         case NOOP_KIND:
  312.             i++;
  313.             break;
  314.         case MSS_KIND:
  315.             optlen = pullchar(bpp);
  316.             if(optlen == MSS_LENGTH)
  317.                 tcph->mss = pull16(bpp);
  318.             i += optlen;
  319.             break;
  320.         }
  321.     }
  322. eol:
  323.     /* Get rid of any padding */
  324.     if(i < hdrlen)
  325.         pullup(bpp,NULLCHAR,hdrlen - i);
  326.     return hdrlen;
  327. }
  328.